import vtkmodules.all as vtk
from CloudEngine.core.TEdge import TEdge
from CloudEngine.core.TLine import TLine
from CloudEngine.Math.Vector3 import Vector3
from CloudEngine.core.LabelActor import LabelActor


class OutLineActor:
    type = "VT_ACTOR"
    create_by = "default"

    mapper = vtk.vtkPolyDataMapper()
    isMesh = False
    virtualLines: list[TLine] = [];

    edgeData: TEdge = None
    EDGE_COLOR = [0, 0, 0, 255]  # 边默认黑色
    SHADER_EDGE_COLOR = [0, 255, 0, 255]  # 共享边绿色
    FREE_EDGE_COLOR = [255, 0, 0, 255]  # 自由边红色
    INTERNAL_EDGE_COLOR = [255, 0, 0, 255]  # 内部边红色

    def __init__(self, edgeData_ins: TEdge):
        self.instance = vtk.vtkActor()
        self.edgeData = edgeData_ins
        self.mapper = self.initMapper()
        self.instance.SetMapper(self.mapper)
        self.instance.SetPickable(True)
        self.createVirtualLine()
        # self.showEdgeColor()        

    def initMapper(self):
        mapper = vtk.vtkPolyDataMapper()
        mapper.InterpolateScalarsBeforeMappingOn()
        mapper.SetScalarModeToUseCellData()
        mapper.SetColorModeToDirectScalars()
        mapper.ScalarVisibilityOn()
        mapper.SetInputData(self.edgeData.polyData)
        mapper.Update()
        inputData = mapper.GetInput()
        if inputData.GetNumberOfCells() == 0:
            inputData.BuildCells()
        self.create_cell_color(mapper, OutLineActor.FREE_EDGE_COLOR)
        return mapper

    def create_cell_color(self, mapper=None, color: list = [255, 255, 0, 255],
                          edge_id=None):
        """修改指定线的颜色"""
        # 获取 PolyData 输入
        if mapper is None:
            mapper = self.mapper

        inputData = mapper.GetInput()
        pd = inputData.GetCellData()
        colors = pd.GetScalars()
        npts = inputData.GetNumberOfCells()  # 获取单元数量，即 cells 数量
        if colors is None:
            # 初始化颜色数组
            colors = vtk.vtkUnsignedCharArray()
            colors.SetNumberOfComponents(4)  # 设置 RGBA 四个分量
            colors.SetName("colors")
            colors.SetNumberOfTuples(npts)  # 确保设置与 cells 数量相同的颜色元组

            for i in range(npts):
                colors.SetTuple4(i, *color)  # 红色，完全不透明

        if edge_id is not None:
            cellId = self.find_cellIdByEdgeId(edge_id)
            if cellId == -1: return
            colors.SetTuple4(cellId, *color)
        pd.SetScalars(colors)
        inputData.Modified()

    def set_line_width(self, width=1):
        self.instance.GetProperty().SetLineWidth(width)

    def showEdgeColor(self):
        if self.edgeData.edgeTypes is None or len(self.edgeData.edgeLineNums) == 0:
            return
        inputData = self.mapper.GetInput()
        pd = inputData.GetCellData()
        colors = pd.GetScalars()
        edgeLen = len(self.edgeData.edgeLineNums)

        for i in range(edgeLen):
            startIdx = 0 if i == 0 else self.edgeData.edgeLineNums[i - 1]
            endIdx = self.edgeData.edgeLineNums[i]
            rgba = OutLineActor.FREE_EDGE_COLOR
            if self.edgeData.edgeTypes[i * 3] == 0:
                rgba = OutLineActor.SHADER_EDGE_COLOR
            elif self.edgeData.edgeTypes[i * 3 + 1] == 2:
                rgba = OutLineActor.INTERNAL_EDGE_COLOR
            j = startIdx
            for j in range(startIdx, endIdx):
                colors.SetTuple4(j, *rgba)
        pd.SetScalars(colors)
        self.mapper.GetInput().Modified()

    def setOpacity(self, opacity):
        self.instance.GetProperty().SetOpacity(opacity)

    def getOpacity(self):
        return self.instance.GetProperty().GetOpacity()

    def setVisible(self, visible: bool):
        self.instance.SetVisibility(visible)

    def getVisible(self):
        return self.instance.GetVisibility()

    def set_render_type(self, render_type):
        if render_type == "HIDDEN":
            self.setVisible(False)
            return
        representation = 0
        edgeVisibility = 0
        self.setVisible(True)
        match render_type:
            case "POINTS":
                representation = 0
                edgeVisibility = 0
            case "WIREFRAME":
                representation = 1
                edgeVisibility = 0
            case "SURFACE":
                representation = 2
                edgeVisibility = 0
            case "SURFACE_WITH_EDGE":
                representation = 2
                edgeVisibility = 1
        if edgeVisibility == 1:
            self.instance.GetProperty().EdgeVisibilityOn()
        else:
            self.instance.GetProperty().EdgeVisibilityOff()

        match representation:
            case 2:
                self.instance.GetProperty().SetRepresentationToSurface()
            # case 1:
            #     self.instance.GetProperty().SetRepresentationToWireframe()
            case 0:
                self.instance.GetProperty().SetRepresentationToSurface()

    def createVirtualLine(self, edgeData_ins: TEdge = None):
        edgeData_ins = edgeData_ins if edgeData_ins is not None else self.edgeData

        polyData = edgeData_ins.polyData
        edgeIds = edgeData_ins.edgeIds
        edgeTypes = edgeData_ins.edgeTypes
        edgeLineNums = edgeData_ins.edgeLineNums
        lines = polyData.GetLines()
        lines.InitTraversal()
        # 遍历所有线单元
        idList = vtk.vtkIdList()
        if polyData is None and edgeTypes is None and edgeIds is None:
            return

        i = 0
        edgeTypeIndex = 0
        edgeIdIndex = 0
        while lines.GetNextCell(idList):
            if idList.GetNumberOfIds() != 2: continue
            p1_id = idList.GetId(0)
            p2_id = idList.GetId(1)

            p1 = polyData.GetPoint(p1_id)
            p2 = polyData.GetPoint(p2_id)
            # 确保索引不超出范围
            if i >= edgeLineNums[edgeTypeIndex] and edgeTypeIndex < len(edgeTypes) - 1:
                edgeTypeIndex += 1
            if edgeIdIndex < len(edgeIds):
                self.virtualLines.append(
                    TLine(
                        Vector3(p1[0], p1[1], p1[2]),
                        Vector3(p2[0], p2[1], p2[2]),
                        edgeTypes[edgeTypeIndex],
                        edgeIds[edgeIdIndex]
                    )
                )
                edgeIdIndex += 1

            i += 1

            # 更新edgeTypeIndex和edgeIdIndex索引
            if edgeIdIndex < len(edgeLineNums) and i == edgeLineNums[edgeIdIndex]:
                edgeIdIndex += 1

    def find_cellIdByEdgeId(self, edge_id):
        for i in range(len(self.edgeData.edgeIds)):
            if self.edgeData.edgeIds[i] == edge_id:
                return i
        return -1
